/*
 * Copyright © 2009 Gerald Isaac Schwarz
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package base;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;

import javax.swing.JLabel;
import javax.swing.border.Border;
import javax.swing.event.EventListenerList;

public class BoardWidget extends JLabel {
	private Board board;
	private Point[][] highlightedSquares;
	private Square focusedSquare, selectedSquare;
	private int zoom;
	private EventListenerList listenerList = new EventListenerList();
	
	public BoardWidget(Board board) {
		this.board = board;
		this.setSize(this.getBoard().getSize());
	}
	
	public void setSize(Dimension size) {
		this.getBoard().setSize(size);
		this.setZoom(this.getZoom());
		this.highlightedSquares = new Point[this.getBoard().getSize().height][this.getBoard().getSize().width];
	}
	
	public Point getLocation(Point coordinate) {
		Rectangle rectangle = new Rectangle(this.getPreferredSize());
		if (rectangle.contains(coordinate)) {
			int width = rectangle.width / this.getBoard().getSize().width;
			int height = rectangle.height / this.getBoard().getSize().height;
			
			return new Point(coordinate.x / width, coordinate.y / height);
		}
		else {
			return null;
		}
	}
	
	public Board getBoard() {
		return this.board;
	}
	
	@Override
	public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		
		Rectangle rectangle = new Rectangle(this.getPreferredSize());
		g2.clearRect(0, 0, this.getSize().width, this.getSize().height);
		int width = rectangle.width / this.getBoard().getSize().width;
		int height = rectangle.height / this.getBoard().getSize().height;
		Rectangle spot = new Rectangle(0, 0, width + 1, height + 1);
		
		Point[][] highlightedSquares = this.getHightlightTargets();
		Square selectedSquare = this.getSelectedSquare();
		Square focusedSquare = this.getFocusedSquare();
		
		int margin = this.getZoom() / 15;
		int border = this.getZoom() / 15;
		
		for (int y = 0; y < this.getBoard().getSize().height; y++) {
			for (int x = 0; x < this.getBoard().getSize().width; x++) {
				Square square = this.getBoard().getSquare(new Point(x, y));
				
				if (highlightedSquares[y][x] != null) {
					g2.setColor(Color.GRAY);
				}
				else if (square == selectedSquare) {
					g2.setColor(Color.LIGHT_GRAY);
				}
				else {
					g2.setColor(square.getColor());
				}
				
				spot.setLocation(x * width, y * height);
				g2.fillRect(spot.x, spot.y, spot.width, spot.height);
				
				if (square.getPiece() != null) {
					Piece piece = square.getPiece();
					State state = this.getBoard().getCurrentState(piece);
					Color color = state.getOwner().getColor();
					String level  = state.getLevel() + "";
					Color fg = new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue());
					Color bg = new Color(color.getRed(), color.getGreen(), color.getBlue());
					
					g2.setColor(fg);
					g2.fillOval((x * width) + margin, (y * height) + margin, width - (margin * 2), height - (margin * 2));
					
					g2.setColor(bg);
					g2.fillOval((x * width) + margin + border, (y * height) + margin + border, width - (margin * 2) - (border * 2), height - (margin * 2) - (border * 2));
					
					g2.setColor(fg);
					int fontSize = height / 3;
					g2.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, fontSize));
					FontRenderContext fontRenderContext = g2.getFontRenderContext();
					TextLayout textLayout = new TextLayout(level, g2.getFont(), fontRenderContext);
					
					Point baseline = new Point((x * width) + (width / 2) - (margin / 2) - (int)(textLayout.getBounds().getWidth() / 2), (y * height) + (height / 2) + (margin / 2) + (int)(textLayout.getBounds().getHeight() / 2));
					
					g2.drawString(level , baseline.x, baseline.y);
				}
			}
		}
		
		if (focusedSquare != null) {
			Point location = focusedSquare.getLocation();
			spot.setLocation(location.x * width, location.y * height);
			g2.setColor(Color.RED);
			for (int i = 0; i < border; i++) {
				g2.drawRect(spot.x + i, spot.y + i, spot.width - 1 - (i * 2), spot.height - 1 - (i * 2));
			}
		}
	}
	
	public void setHightlightTargets(Point[][] points) {
		if (points != null) {
			this.highlightedSquares = points;
		}
		else {
			this.highlightedSquares = new Point[this.getBoard().getSize().height][this.getBoard().getSize().width]; 
		}
	}
	
	public Point[][] getHightlightTargets() {
		return this.highlightedSquares;
	}
	
	public void setSelectedSquare(Point location) {
		if (location != null) {
			this.selectedSquare = this.getBoard().getSquare(location);
		}
		else {
			this.selectedSquare = null;
		}
	}
	
	public Square getSelectedSquare() {
		return this.selectedSquare;
	}
	
	public void setFocusedSquare(Point location) {
		if (location != null) {
			this.focusedSquare = this.getBoard().getSquare(location);
		}
		else {
			this.focusedSquare = null;
		}
	}

	public Square getFocusedSquare() {
		return this.focusedSquare;
	}

	public Square getSquare(Point point) {
		return this.getBoard().getSquare(point);
	}
	
	public void setZoom(int zoom) {
		this.zoom = zoom;
		this.setPreferredSize(new Dimension(this.getBoard().getSize().width * this.zoom, this.getBoard().getSize().height * this.zoom));
		this.notifyZoomListeners(new ZoomEvent(this));
	}
	
	public int getZoom() {
		return this.zoom;
	}
	
	public void addZoomListener(ZoomListener zoomListener) {
		this.listenerList.add(ZoomListener.class, zoomListener);
	}
	
	private void notifyZoomListeners(ZoomEvent zoomEvent) {
		Object[] listeners = listenerList.getListenerList();
		
		for (int i = 0; i < listeners.length; i += 2) {
			if (listeners[i] == ZoomListener.class) {
            	((ZoomListener)listeners[i + 1]).zoomChanged(zoomEvent);
            }
        }
	}
}
